from fastapi import APIRouter, Depends
from sqlmodel import Session, select
from crud import menu as menu_crud
from common import response_code, exception
import models
import utility
from dependencies import SessionDep, engine
from typing import Annotated
from routers.auth import get_current_sys_user


router = APIRouter()


"""查询用户拥有权限的全部菜单

Keyword arguments: 
None
Return: response -- 响应体
"""


@router.get(
    "/api/system/menus",
    tags=["菜单管理"],
    summary="查询当前用户拥有权限菜单",
    response_model=models.RespJsonMenu,
)
async def get_menu_list(
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_200),
):
    # 查询用户拥有的角色
    user_roles = user.roles

    if len(user_roles) > 0:

        # 初始化组合角色拥有的菜单id
        menu_list_id = set([])

        # 组合角色拥有的菜单id并去重
        for user_role in user_roles:
            # 查询角色拥有的菜单
            role_menus = session.get(models.SystemRole, user_role.id).menus

            # 查询角色拥有菜单的id列表
            role_menus_id = [i.id for i in role_menus]

            # 组合角色拥有的菜单id并去重
            menu_list_id = menu_list_id | set(role_menus_id)

        # 将set转换为list
        menu_list_id = list(menu_list_id)

        # 查询菜单数据
        menus = session.exec(
            select(models.SystemMenu).where(
                models.SystemMenu.id.in_(menu_list_id)
            ).order_by(models.SystemMenu.order)
        ).all()

    else:
        # 如果用户没有角色，则查询系统全部菜单
        menus = session.exec(
            select(models.SystemMenu).order_by(models.SystemMenu.order)
        ).all()

    # 用户是否有菜单权限
    if not menus:
        raise exception.create_http_exception(
            status_code=403, detail="用户无菜单权限")

    # 将查询的结果构按照树状结构返回
    response.data = utility.general.build_tree_recursive(menus)

    response.msg = "查询成功"

    return response


"""查询全部菜单

Keyword arguments:
None
Return: return_description
"""


@router.get(
    "/api/system/menus/all",
    tags=["菜单管理"],
    summary="查询全部菜单",
    response_model=models.RespJsonMenu,
)
async def get_all_menu(
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_200),
):
    # 获取全部菜单
    items = session.exec(select(models.SystemMenu).order_by(
        models.SystemMenu.order)).all()

    # 将查询的结果构按照树状结构返回
    response.data = utility.general.build_tree_recursive(items)

    response.msg = "查询成功"

    return response


"""查询可用的菜单

Keyword arguments:
None
Return: return_description
"""
@router.get(
    "/api/system/menus/available",
    tags=["菜单管理"],
    summary="查询可用菜单",
    response_model=models.RespJsonMenu,
)
async def get_available_menu(
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_200),
):
    # 查询可用菜单
    items = session.exec(
        select(models.SystemMenu).where(models.SystemMenu.is_active == True)
    ).all()

    # 将查询的结果构按照树状结构返回
    response.data = utility.general.build_tree_recursive(items)

    response.msg = "查询成功"

    return response


"""新增菜单

Keyword arguments:
menu -- 新增菜单参数
Return: response -- 响应体
"""


@router.post(
    "/api/system/menus",
    tags=["菜单管理"],
    summary="新增菜单",
    response_model=models.RespJsonMenu,
)
async def create_menu(
    menu: models.SystemMenuCreate,
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_201),
):

    # 查询同名菜单
    found_menu = menu_crud.get_menu(name=menu.name, session=session)

    # 校验父级菜单是否有效
    if (
        menu.parent_id and session.get(
            models.SystemMenu, menu.parent_id) is None
    ) or menu.parent_id == 0:
        raise exception.create_http_exception(
            status_code=400, detail="父级菜单不存在")
    elif found_menu:
        raise exception.create_http_exception(
            status_code=400, detail="菜单名称已存在")
    # 校验父级菜单不能为自己
    elif menu.parent_id == id:
        raise exception.create_http_exception(
            status_code=400, detail="父级菜单不能为当前菜单")

    # 新增菜单
    menu_crud.create_menu(menu, user, session)

    response.msg = "新增成功"
    return response


"""编辑菜单

Keyword arguments:
id -- 菜单id
menu -- 菜单更新参数
Return: response -- 响应体
"""


@router.put(
    "/api/system/menus/{id}",
    tags=["菜单管理"],
    summary="编辑菜单",
    response_model=models.RespJsonMenu,
)
async def update_menu(
    id: int,
    menu: models.SystemMenuUpdate,
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_202),
):

    # 查询菜单名称是否已存在
    found_menu = menu_crud.get_menu(name=menu.name, session=session)

    # 已存在菜单id列表
    menu_list_id = [i.id for i in found_menu]

    # 校验父级菜单是否有效
    if (
        menu.parent_id and session.get(
            models.SystemMenu, menu.parent_id) is None
    ) or menu.parent_id == 0:
        raise exception.create_http_exception(
            status_code=400, detail="父级菜单不存在")
    # 校验菜单名称是否已存在
    elif found_menu and id not in menu_list_id:
        raise exception.create_http_exception(
            status_code=400, detail="菜单名称已存在")
    # 校验父级菜单不能为自己
    elif menu.parent_id == id:
        raise exception.create_http_exception(
            status_code=400, detail="父级菜单不能为当前菜单")

    # 更新菜单
    menu_crud.update_menu(id, menu, user, session)

    response.msg = "编辑成功"

    return response


"""删除菜单

Keyword arguments:
id -- 菜单id
Return: response -- 响应体
"""


@router.delete(
    "/api/system/menus/{id}",
    tags=["菜单管理"],
    summary="删除菜单",
    response_model=models.RespJsonMenu,
)
async def delete_menu(
    id: int,
    user: Annotated[models.SystemUser, Depends(get_current_sys_user)],
    session: SessionDep = Session(engine),
    response: models.RespJsonMenu = Depends(
        response_code.RespSuccessJson.resp_204),
):
    # 查询菜单数据
    system_menu = session.get(models.SystemMenu, id)
    # 如果菜单数据不存在，则抛出异常
    if not system_menu:
        raise exception.create_http_exception(status_code=400, detail="菜单不存在")
    # 删除菜单
    menu_crud.delete_menu(id, user, session)

    response.msg = "删除成功"
    return response
